package com.beesphere.products.throttling.impl;

import java.util.Map;
import java.util.Set;

import com.beesphere.products.throttling.Throttler;
import com.beesphere.products.throttling.ThrottlingAgent;
import com.beesphere.products.throttling.UnitOfWork;
import com.beesphere.products.throttling.UnitOfWorkCapacity;
import com.beesphere.products.throttling.executor.ExecutorServiceFactory;
import com.beesphere.products.throttling.executor.impl.DefaultExecutorServiceFactory;

public abstract class DefaultThrottlingAgent implements ThrottlingAgent {

	private static final long serialVersionUID = -2212765223326170988L;
	
	protected ExecutorServiceFactory executorServiceFactory = new DefaultExecutorServiceFactory ();

	protected Map<String, Throttler> throttlersStack;

	@Override
	public Throttler lookup (UnitOfWork uow) throws Exception {
		Throttler t = throttlersStack.get (getAdequateThrottler (uow));
		if (t == null) {
			UnitOfWorkCapacity capacity = capacityFor (uow);
			if (capacity == null) {
				t = throttlersStack.get (SHARED_THROTTLER);
			} else {
				t = register (uow.getId (), capacity);
			}
		}
		return t;
	}
	
	protected String getAdequateThrottler (UnitOfWork uow) throws Exception {
		return uow.getId ();
	}

	protected boolean useThrottler (String id, Set<String> uows) {
		if (uows == null || uows.isEmpty ()) {
			return false;
		}
        for(String uow : uows) {
        	if (id.matches (uow)) {
                return true;
            }
        }
        return false;
	}

	@Override
	public Throttler register (String id, UnitOfWorkCapacity capacity) throws Exception {
		Throttler t = throttlersStack.get (id);
		if (t == null) {
			t = new PoolBasedThrottler (executorServiceFactory, capacity);
			t.start ();
			throttlersStack.put (id, t);
		}
		return t;
	}

	public Map<String, Throttler> getThrottlersStack() {
		return throttlersStack;
	}

	public void setThrottlersStack(Map<String, Throttler> throttlersStack) {
		this.throttlersStack = throttlersStack;
	}
	
	public void shutdown () {
		if (throttlersStack == null || throttlersStack.isEmpty ()) {
			return;
		}
		for (Throttler t : throttlersStack.values ()) {
			try {
				t.stop ();
			} catch (Exception e) {
				// IGNORE
			}
		}
	}

	public ExecutorServiceFactory getExecutorServiceFactory() {
		return executorServiceFactory;
	}

	public void setExecutorServiceFactory(
			ExecutorServiceFactory executorServiceFactory) {
		this.executorServiceFactory = executorServiceFactory;
	}

}
